﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics.Contracts;
using System.Linq.Expressions;

namespace ReactiveCode.Expressions
{
    using Observables;

    [System.Diagnostics.DebuggerTypeProxy(typeof(IfExpression.DebugView))]
    class IfExpression : ReactiveExpression, IExpressionParent
    {
        #region DebugView

        class DebugView
        {
            IfExpression _expr;

            public DebugView(IfExpression expr)
            {
                Contract.Requires(expr != null);
                _expr = expr;
            }

            public string Condition
            {
                get { return _expr.Condition; }
            }

            public bool ConditionValue
            {
                get { return _expr._conditionValue; }
            }

            public ReactiveExpression IfTrue
            {
                get { return _expr._trueExpression; }
            }

            public ReactiveExpression IfFalse
            {
                get { return _expr._falseExpression; }
            }

            public bool Enabled
            {
                get { return _expr.Enabled; }
            }
        }

        #endregion

        ReactiveExpression _trueExpression, _falseExpression, _currentExpression;
        IDisposable _subscription;
        List<ReactiveExpression> _children = new List<ReactiveExpression>();
        bool _conditionValue;

        public string Condition { get; set; }

        public IfExpression(ObservableFactory<IObservable<bool>> test, ReactiveExpression trueExpression, ReactiveExpression falseExpression)
        {
            Contract.Requires(test != null && trueExpression != null);

            if (trueExpression != null)
            {
                _trueExpression = trueExpression;
                _children.Add(_trueExpression);
                _trueExpression.Parent = this;
            }
            if (falseExpression != null)
            {
                _falseExpression = falseExpression;
                _children.Add(_falseExpression);
                _falseExpression.Parent = this;
            }

            Contract.Assert(_children.Any());

            EnabledProperty.Subscribe(value =>
            {
                if (_currentExpression != null)
                    _currentExpression.Enabled = value;
            });
            _subscription = Extract(test).Subscribe(x =>
            {
                _conditionValue = x;
                if (_trueExpression != null)
                    _trueExpression.Enabled = x && Enabled;
                if (_falseExpression != null)
                    _falseExpression.Enabled = !x && Enabled;
                _currentExpression = x ? _trueExpression : _falseExpression;
            });
        }
        public override void Dispose()
        {
            base.Dispose();
            _subscription.Dispose();
            if (_trueExpression != null)
                _trueExpression.Dispose();
            if (_falseExpression != null)
                _falseExpression.Dispose();
        }

        #region IExpressionParent Members

        IList<ReactiveExpression> IExpressionParent.Children
        {
            get { return _children; }
        }

        #endregion
    }
}
